package com.nuonuo.middleware.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author duan
 * @version 1.0
 * @date 2024/3/7 15:29
 */
public class HttpClientUtil extends Thread {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class);

    /**
     * Content Type
     */
    public static final String APPLICATION_JSON = "application/json";
    private static CloseableHttpClient httpClient;
    private static PoolingHttpClientConnectionManager connManager;
    private static HttpClientBuilder httpClientBuilder;


    static {
        try {
            // 证书受信配置
            SSLContext sslContext = SSLContextBuilder.create().useProtocol(SSLConnectionSocketFactory.SSL)
                    .loadTrustMaterial((x, y) -> true).build();
            RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build();
            // SSLContext.getDefault()
            LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", sslsf)
                    .build();
            connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            connManager.setMaxTotal(200);
            connManager.setDefaultMaxPerRoute(20);
            // 设置代理HttpHost
            HttpHost proxy = new HttpHost("192.168.212.46", 3128, "http");
            // 设置认证
            CredentialsProvider provider = new BasicCredentialsProvider();
            provider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("", ""));
            httpClient = HttpClients.custom()
                    .setConnectionManager(connManager)
                    // 证书受信配置
                    .setDefaultRequestConfig(config)
                    .setDefaultCredentialsProvider(provider)
                    .setSSLHostnameVerifier((x, y) -> true)
                    .build();
            new HttpClientUtil().start();
        } catch (NoSuchAlgorithmException e) {
            LOGGER.error("创建http客户端异常",e);
        } catch (Exception e){
            LOGGER.error("创建http客户端异常",e);
        }
    }

    private static CloseableHttpClient getHttpClient() {

    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(3000);
                //关闭异常连接
                connManager.closeExpiredConnections();
                //关闭空闲连接
                connManager.closeIdleConnections(6, TimeUnit.SECONDS);
            } catch (Exception e) {
                LOGGER.error("清理异常连接异常", e);
            }
        }
    }

    public static String get(String url, int timeout, Map<String, String> headerMap) throws Exception {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(getRequestConfig(timeout));
        if (null != headerMap && !headerMap.isEmpty()) {
            for (String key : headerMap.keySet()) {
                httpGet.addHeader(key, headerMap.get(key));
            }
        }
        return getResponse(httpGet);
    }


    public static String getWithProxy(String url, int timeout, Map<String, String> headerMap) throws Exception {

        HttpHost httpHost = new HttpHost("192.168.212.46", 3128, "http");
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(getRequestConfig(timeout, httpHost));
        if (null != headerMap && !headerMap.isEmpty()) {
            for (String key : headerMap.keySet()) {
                httpGet.addHeader(key, headerMap.get(key));
            }
        }
        return getResponse(httpGet,null, httpHost, true);
    }


    /**
     * 获取HTTP请求配置
     *
     * @param timeout 超时时间
     * @return RequestConfig
     */
    private static RequestConfig getRequestConfig(int timeout) {
        return RequestConfig.custom()
                .setSocketTimeout(timeout)
                .setConnectTimeout(timeout)
                .setConnectionRequestTimeout(timeout)
                .build();
    }


    /**
     * 获取HTTP请求配置
     *
     * @param timeout 超时时间
     * @return RequestConfig
     */
    private static RequestConfig getRequestConfig(int timeout, HttpHost httpHost) {
        return RequestConfig.custom()
                .setSocketTimeout(timeout)
                .setConnectTimeout(timeout)
                .setConnectionRequestTimeout(timeout)
                .setProxy(httpHost)
                .build();
    }

    /**
     * 获取响应结果
     *
     * @param request 请求
     * @return HTTP response
     */
    private static String getResponse(HttpUriRequest request){
        return getResponse(request,null,null, true);
    }

    /**
     * 获取响应结果
     *
     * @param request 请求
     * @param charset 编码
     * @return HTTP response
     */
    private static String getResponse(HttpUriRequest request,String charset, HttpHost httpHost, boolean entityToStringFlag) {
        CloseableHttpResponse response = null;
        String params = null;
        String res = null;
        try {
            try {
                if(request instanceof HttpPost){
                    HttpEntity reqEntity = ((HttpPost) request).getEntity();
                    if (reqEntity != null && !(reqEntity instanceof MultipartEntity) && entityToStringFlag) {
                        params = EntityUtils.toString(reqEntity);
                    }
                }
            } catch (Exception e) {
                LOGGER.error("getReqEntity error, exception:",e);
            }
            if (httpHost != null) {
                response = httpClient.execute(httpHost, request);
            } else {
                response = httpClient.execute(request);
            }

            if (response.getStatusLine().getStatusCode() == 200) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    if(StringUtils.isNotBlank(charset)){
                        res = EntityUtils.toString(entity,charset);
                    }else {
                        res = EntityUtils.toString(entity);
                    }
                    LOGGER.info(request.getURI() + ",getResponse:" + res + ",params:" + params);
                }else{
                    LOGGER.info(request.getURI() + ",getResponse error,entity is null." + ",params:" + params);
                }
            }else{
                LOGGER.info(request.getURI() + ",getResponse error,statusCode:" + response.getStatusLine().getStatusCode() + ",params:" + params);
            }
        } catch (Exception e) {
            LOGGER.warn(request.getURI()+"","请求异常"+ ",params:" + params,e);
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return res;
    }

}
